home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / New System Software Extensions / QuickDraw™ GX 1.1.2 / Programming Stuff / Sample Code / General QDGX App Samples / QuickDraw GX Scrolling ƒ / QD GX Scrolling (main).c next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  40.4 KB  |  1,375 lines  |  [TEXT/KAHL]

  1. /**
  2.  --        App:        QuickDraw GX Scrolling
  3.  --
  4.  --        File:        GX Scrolling (main).c 
  5.  --
  6.  --        Comments:    This code demonstrates scrolling of a window containing GX shapes. I create
  7.  --                    a window in the CreateDocumentWindow function. At this point, I attach a 
  8.  --                    parent viewPort to the window, and a child viewPort to the parent. This 
  9.  --                    approach enables our application to accommodiate scroll bars and adjust
  10.  --                    the child viewPort's gxMapping to reflect scrolling of the window's contents.
  11.  --
  12.  --                    You might be wondering, why not just perform the same actions on the parent
  13.  --                    viewPort attached to the window? You cannot manipulate the viewPort attached
  14.  --                    to the window. All of it's attributes are maintained by the GX system. This
  15.  --                    leads to a clipping problems because scroll bars are not really part of the
  16.  --                    window's definition.
  17.  --
  18.  --                    Therefore, we attach the child viewPort to set it's clip shape within the
  19.  --                    scroll bars. Also, we update the mapping of this viewPort when the user scrolls,
  20.  --                    thereby guaranteeing that all of the shapes are re-drawn in their correct location.
  21.  --                    Another approach, would be to update the location of each shape contained in the 
  22.  --                    window after scrolling. This would require a lot of work on the application's part. 
  23.  --                    You would also need to undo this operation at print time because your shapes 
  24.  --                    would not reside in their correct location relative to a page.
  25.  --
  26.  --                    If you are interested in finding the GX additions required to run on a GX
  27.  --                    system, search for "GX Additions". If you are only interested in the additions
  28.  --                    required to support scrolling in a GX world, search on "GX Scrolling". 
  29.  --
  30.  --                    The file titled: "GX Scrolling Controls.c" contains of the code required to 
  31.  --                    maintain, draw, and update the scroll bars.
  32.  --
  33.  --
  34.  --        Version:    1.0     1/93      
  35.  --                            => added general GX support & scrolling 
  36.  --
  37.  --
  38.  --        Components:    QD GX Scrolling (main).c
  39.  --                    QD GX Scrolling (main).h
  40.  --                    QD GX Scrolling Controls.c
  41.  --                    QD GX Scrolling Controls.h
  42.  --                    QD GX Scrolling (main).π.rsrc
  43.  --
  44.  --
  45.  --        Bugs:        If you zoom the window onto a montior which is bigger than the default, you
  46.  --                    will receive a GRAPHICS WARNING about how the gxPoint does not intersect the 
  47.  --                    current gxViewPort. From that gxPoint on, until you resize the window to a smaller
  48.  --                    size scrolling will not work correctly. You can create this problem by zooming
  49.  --                    from an Apple 16" monitor to a portrait monitor.
  50.  --                    
  51.  --                    I'm currently working on resolving this problem.
  52.  --
  53.  --
  54.  --        Notes:        1) Print this file in landscape for the best results
  55.  --                    2) If you are using THINK C v5.x, I have added THINK markers to navigate the code.
  56.  --                    3) This code was adapted and simplyified from the "DTS AE Skeleton" sample.
  57.  --
  58.  --
  59.  --        Future
  60.  --        Additions:    1) This code should check to make sure it is running under System 7.1 and the
  61.  --                       GX system is installed.
  62.  --
  63.  --
  64.  --        Author:        Pete "Luke" Alexander
  65.  --                    Developer Technical Support
  66.  --                    AppleLink: DEVSUPPORT
  67.  --
  68.  --        
  69.  --        ©1992 - 1993  Apple Computer, Inc. 
  70.  --        All rights reserved.
  71.  --
  72.  **/
  73.  
  74. #include <AppleEvents.h>
  75. #include <Desk.h>
  76. #include <Dialogs.h>
  77. #include <DiskInit.h>
  78. #include <Errors.h>
  79. #include <Fonts.h>
  80. #include <GestaltEqu.h>
  81. #include <Menus.h>
  82. #include <Memory.h>
  83. #include <OSEvents.h>
  84. #include <OSUtils.h>
  85. #include <Quickdraw.h>
  86. #include <Resources.h>
  87. #include <Script.h>
  88. #include <StandardFile.h>
  89. #include <ToolUtils.h>
  90. #include <Windows.h>
  91.  
  92. #include "QD GX Scrolling (main).h"
  93. #include "QD GX Scrolling Controls.h"
  94.  
  95. #include "graphics toolbox.h"
  96. #include "graphics routines.h"
  97. #include "graphics libraries.h"
  98. #include "graphics debugging.h"
  99.  
  100.  
  101. //
  102. // Prototypes
  103. //
  104. void HandleEvent(void);
  105. void HandleMouseDown(EventRecord *theEvent);
  106. void HandleKeyPress(EventRecord *theEvent);
  107. void HandleDiskEvent(EventRecord *theEvent);
  108. void HandleOSEvent(EventRecord *theEvent);
  109.  
  110. void DoGrowWindow(WindowPtr theWindow, Point where);
  111. void DoZoomWindow(WindowPtr theWindow, short thePart);
  112. void ActivateWindow(WindowPtr theWindow, Boolean activate);
  113. void FitWindowOnDevice(Rect *windRect, Rect *deviceRect);
  114. Rect GetDeviceRect(WindowPtr theWindow);
  115.  
  116. void DoMenu(long menuChoice);
  117. void DoOpenCommand(void);
  118. void DoPrintCommand(void);
  119. void PrintDocument(PicHandle thePicture);
  120.  
  121. PicHandle ReadDocument(FSSpecPtr mySpec);
  122. Boolean CreateDocumentWindow(PicHandle thePicture, Str63 name);
  123. void CloseFrontWindow(void);
  124. void DrawWindow(WindowPtr theWindow);
  125. void AdjustMenus(void);
  126.  
  127. void ToolBoxInit(void);
  128. void MenuBarInit(void);
  129. void PrintInit(void);
  130. Boolean ColorQDAvail(void);
  131. Boolean FileRoutinesAvail(void);
  132. void ErrorAlert(short errNumber, Boolean fatal);
  133. void ShutdownProgram(void);
  134.  
  135. //
  136. // The following functions were added to support GX, and add scrolling window support.
  137. //
  138. void QuickDrawGXInit(void);
  139. void GetWindowBoundsShape(WindowPtr myWindow, gxRectangle *boundingBoxPtr);
  140. gxShape CreateThePageOfGXShapes (gxShape thePage);
  141. void ResetContentViewPortClip (WindowPtr theWindow);
  142.  
  143.  
  144. /* This routine is part of the MPW runtime library. This external
  145.    reference to it is done so that we can unload its segment, %A5Init. */
  146. #ifndef THINK_C
  147.   extern void _DataInit();
  148. #endif
  149.  
  150.  
  151. //
  152. // Global Variables
  153. //
  154. Boolean                gDone;            /* Has the user selected quit? */
  155. gxGraphicsClient     gGraphicsClient;
  156.  
  157.  
  158. //
  159. //    The variables from this gxPoint on, were added to support QuickDraw™ GX.
  160. //
  161.  
  162. //
  163. //    gthePage contain all of the GX shapes which are displayed in the window. gthePage is defined
  164. //    as a gxPictureType in the function CreateShapes. CreateShapes creates all of the shapes
  165. //    contained in gthePage.
  166. // 
  167. gxShape                gthePage;
  168.  
  169. //
  170. //    This viewPort is the child attached to the window's parent viewPort. Since it is a child viewPort,
  171. //    we (the application) need to maintain the clip shape. We also have the ability to manipulate this
  172. //    ViewPort as we see fit, therefore we adjust the mapping, to reflect scrolling changes by the user.
  173. //
  174. gxViewPort            gcontentViewPort;
  175.  
  176.  
  177. // 
  178. //    If gDebugging = TRUE, graphics library errors and notices will be posted.  This functionality  will only work with 
  179. //    the "debugging" version of the QuickDraw init.  If this version of the init is not installed, nothing bad will happen, 
  180. //    but these  functions will not work.
  181. //
  182. Boolean                gDebugging = true;
  183.  
  184. //
  185. //  Set gGiveMeValidation = TRUE, if you will receive run-time validation. 
  186. //
  187. Boolean                gGiveMeValidation = true;
  188.  
  189.  
  190. //     
  191. //    gGraphicsHeapSize sets the size of the graphics gxHeap created by calling the GXNewGraphicsClient routine
  192. //    in main () within graphics shell.c.  You can determine the amount of graphics gxHeap required by using GraphicsBug.
  193. //    With  gGraphicsHeapSize set to 25k, I had 2 free blocks left in the graphics gxHeap. Sounds good to me.
  194. //
  195. long            gGraphicsHeapSize = 25;
  196.  
  197.  
  198.  
  199. /**----- main --------------------------------------------------------------------------------
  200.  --
  201.  --     Main initializes the application memory, toolbox, menubar, the GX world, and global 
  202.  --        variables. We also create a document & window containing our GX picture, which contains
  203.  --        all of our rectangles.
  204.  --
  205.  **/
  206. main()
  207. {
  208. #ifndef THINK_C
  209.     UnloadSeg((Ptr) _DataInit);        /* note that _DataInit must not be in Main! */
  210. #endif
  211.  
  212.     ToolBoxInit();
  213.     MenuBarInit();
  214.     QuickDrawGXInit();    //    This function initializes the GX system
  215.     PrintInit();
  216.  
  217.     gDone = false;            /* Initialize global variables */
  218.  
  219.     CreateDocumentWindow(nil, "\p QuickDraw GX Scrolling ");
  220.  
  221.     while (!gDone)
  222.         HandleEvent();
  223.     
  224.     ExitToShell();    
  225. }
  226.  
  227.  
  228. /**----- ToolBoxInit -------------------------------------------------------------------------
  229.  --
  230.  --        This function initializes the toolbox.
  231.  --
  232.  **/
  233. void ToolBoxInit(void)
  234. {
  235.     EventRecord    theEvent;
  236.     short        count;
  237.     
  238.     /**   Generic gxHeap initialization.  **/
  239.     MaxApplZone(); 
  240.     MoreMasters(); MoreMasters(); MoreMasters(); 
  241.     MoreMasters(); MoreMasters(); MoreMasters(); 
  242.  
  243.     InitGraf (&qd.thePort);
  244.     InitFonts ();
  245.     FlushEvents(everyEvent, 0);
  246.     InitWindows();
  247.     InitMenus();
  248.     TEInit();
  249.     InitDialogs(nil);
  250.     InitCursor();
  251.     
  252.     /* Multi-finder brings our application to the front after */
  253.     /* we ask for three events. */
  254.     for (count=3; count!=0; count--)
  255.         EventAvail(everyEvent, &theEvent);
  256. }
  257.  
  258.  
  259. /**----- MenuBarInit -------------------------------------------------------------------------
  260.  --
  261.  --     This function initializes the menus, and installs DAs in the Apple Menu.
  262.  --
  263.  **/
  264. void MenuBarInit(void)
  265. {
  266.     Handle        theMenuBar;
  267.     MenuHandle    appleMenu;
  268.     
  269.     /* Install menus from resources */
  270.     theMenuBar = GetNewMBar(rMenuBar);
  271.     if (theMenuBar == nil)
  272.         ErrorAlert(kNoMenuBarErr, true);
  273.     SetMenuBar(theMenuBar);
  274.     DisposHandle(theMenuBar);
  275.     
  276.     /* Add desk accessories to Apple Menu */
  277.     appleMenu = GetMHandle(mApple);
  278.     if (appleMenu != nil)
  279.         AddResMenu(appleMenu, kDriverType);
  280.  
  281.     DrawMenuBar();
  282. }
  283.  
  284.  
  285.  
  286. /**----- QuickDrawGXInit ---------------------------------------------------------------------
  287.  --
  288.  --        This function makes all of the calls required to gxInitialize the GX system, except 
  289.  --        for the printing part. For complete details regarding each call made, please see
  290.  --        the comment blocks.                                                    (GX Addition)
  291.  --                                                 
  292.  **/
  293. void QuickDrawGXInit(void)
  294. {
  295.     //     
  296.     //    The GXNewGraphicsClient routine defines the graphics gxHeap size. If you do not make this call, 
  297.     //    the GX graphics engine will create this gxHeap automatically. How? It will create a graphics
  298.     //    gxHeap of 600k. This call allows you to explicity define the ammount of memory used by the 
  299.     //  graphics system to store it's graphics objects gxHeap.
  300.     //
  301.     //    If you do not pass a value for gGraphicsHeapSize, you will receive the default graphics gxHeap.
  302.     //    The GX system will automatically page objects to disk when memory is low.
  303.     //
  304.     gGraphicsClient = GXNewGraphicsClient(nil, gGraphicsHeapSize * 1024, 0L);
  305.  
  306.  
  307.     // 
  308.     //    If gDebugging = TRUE, you will receive graphics library errors & notices will be posted.  This
  309.     //    functionality will only work with the "debugging" version of the Secret Graphics init.  If this
  310.     //    init is not installed, these functions will not work. The "debugging" version of the Secret 
  311.     //    Graphics init is approximately 810K.
  312.     //
  313.     if (gDebugging) {
  314.         SetGraphicsLibraryErrors ();
  315.         SetGraphicsLibraryNotices();    
  316.     }
  317.  
  318.  
  319.     // 
  320.     //    Set  "gGiveMeValidation" to TRUE, if you want run-time validation. As you increase the amount
  321.     //    of validation, The drawing speed will SLOW down due to all of the internal checking. 
  322.     //    
  323.     //    gxPublicValidation will check parameters to public routines. For additional details regarding 
  324.     //    the various levels of validation, please see the documentation.
  325.     //
  326.     if (gGiveMeValidation) GXSetValidation(gxPublicValidation); 
  327.  
  328.  
  329.     //
  330.     //  Create the default data structures.
  331.     //
  332.     GXEnterGraphics();
  333.  
  334.  
  335.     //
  336.     //    Initialize the common colors library defined in "gxColor library.c" and "graphics library.h".
  337.     //    This library is a simple method available for you to gxColor an object quickly by calling the
  338.     //    the SetShapeCommonColor(...) function.
  339.     //
  340.      InitCommonColors();
  341. }
  342.  
  343.  
  344.  
  345. /**----- PrintInit ---------------------------------------------------------------------------
  346.  --
  347.  --        This function will someday gxInitialize the GX Print Manager, if it is present.
  348.  --
  349.  **/
  350. void PrintInit(void)
  351. {
  352.  
  353. }
  354.  
  355.  
  356.  
  357. /**----- HandleEvent -------------------------------------------------------------------------
  358.  --
  359.  --        This function contains the main event loop.
  360.  --
  361.  **/
  362. void HandleEvent(void)
  363. {
  364.     EventRecord    theEvent;
  365.     OSErr        myErr;
  366.     WindowPtr    theWindow;
  367.     
  368.     WaitNextEvent(everyEvent, &theEvent, 30, nil);
  369.  
  370.     switch (theEvent.what)
  371.     {
  372.     case mouseDown:
  373.         HandleMouseDown(&theEvent);
  374.         break;
  375.     
  376.     case keyDown:
  377.     case autoKey:
  378.         HandleKeyPress(&theEvent);
  379.         break;
  380.     
  381.     case updateEvt:
  382.         theWindow = (WindowPtr)theEvent.message;
  383.         BeginUpdate(theWindow);
  384.         if (!EmptyRgn(theWindow->visRgn))
  385.         {
  386.             SetPort(theWindow);
  387.             UpdtControl(theWindow, theWindow->visRgn);
  388.             DrawGrowIcon(theWindow);
  389.             DrawWindow(theWindow);
  390.         }
  391.         EndUpdate(theWindow);
  392.     
  393.     case diskEvt:
  394.         HandleDiskEvent(&theEvent);
  395.         break;
  396.  
  397.     case activateEvt:
  398.         ActivateWindow((WindowPtr)theEvent.message, theEvent.modifiers & activeFlag);
  399.         break;
  400.     
  401.     case osEvt:
  402.         HandleOSEvent(&theEvent);
  403.         break;
  404.     
  405.     case kHighLevelEvent:
  406.         myErr = AEProcessAppleEvent(&theEvent);
  407.         if  (myErr != noErr)
  408.         {
  409.             ErrorAlert(kAppleEventErr, false);
  410.         }
  411.         break;
  412.     }
  413. }
  414.  
  415.  
  416. /**----- HandleMouseDown ---------------------------------------------------------------------
  417.  --
  418.  --        This functions is called whenever the mouse button is pressed. It finds the mouse 
  419.  --        location when the button was pressed and routes the event appropriately.
  420.  --
  421.  **/
  422. void HandleMouseDown(EventRecord *theEvent)
  423. {
  424.     short            thePart;
  425.     WindowPtr        theWindow;
  426.     Rect            theRect;
  427.     short            controlPart;
  428.     ControlHandle    theControl;
  429.  
  430.     thePart = FindWindow(theEvent->where, &theWindow);
  431.     switch (thePart)
  432.     {
  433.     case inMenuBar:
  434.         AdjustMenus();
  435.         DoMenu(MenuSelect(theEvent->where));
  436.         break;
  437.     
  438.     case inSysWindow:
  439.         SystemClick(theEvent, theWindow);
  440.         break;
  441.     
  442.     case inContent:
  443.         if (theWindow != FrontWindow())
  444.             SelectWindow(theWindow);
  445.         else
  446.         {
  447.             SetPort(theWindow);
  448.             GlobalToLocal(&theEvent->where);
  449.             controlPart = FindControl(theEvent->where, theWindow, &theControl);
  450.             if (controlPart != 0)
  451.                 DoControl(theEvent->where, theControl, controlPart);
  452.         }
  453.         break;
  454.  
  455.     case inDrag:
  456.         if (theWindow != FrontWindow())
  457.             SelectWindow(theWindow);
  458.         theRect = (**GetGrayRgn()).rgnBBox;
  459.         DragWindow(theWindow, theEvent->where, &theRect);
  460.         break;
  461.     
  462.     case inGrow:
  463.         DoGrowWindow(theWindow, theEvent->where);
  464.         break;
  465.  
  466.     case inGoAway:
  467.         if (TrackGoAway(theWindow, theEvent->where))
  468.           ShutdownProgram();
  469.         break;
  470.     
  471.     case inZoomIn:
  472.     case inZoomOut:
  473.         if (TrackBox(theWindow, theEvent->where, thePart))
  474.             DoZoomWindow(theWindow, thePart);
  475.         break;
  476.     }
  477. }
  478.  
  479.  
  480.  
  481. /**----- ResetContentViewPortClip ------------------------------------------------------------
  482.  --
  483.  --        This function resets the clip gxShape of the "gcontentViewPort", to represent the new
  484.  --        clip gxShape after the user has zoomed or resized the window.           (GX Scrolling)
  485.  --
  486.  **/
  487. void ResetContentViewPortClip (WindowPtr theWindow)
  488. {
  489.     gxRectangle    viewRect;
  490.     gxShape        contentViewPortClipShape;
  491.  
  492.     //
  493.     //    Return a fixed gxPoint gxRectangle in "viewRect" which represents the portRect of the
  494.      //    window. This gxShape will be used as the new clip gxShape for "gcontentViewPort".
  495.     GetWindowBoundsShape(theWindow, &viewRect);
  496.  
  497.     //
  498.     // Adjust our viewRect to accommodate the scroll bars
  499.     //
  500.     viewRect.right -= ff(kScrollBarWidth - 1);    
  501.     viewRect.bottom -= ff(kScrollBarWidth - 1);
  502.  
  503.     //
  504.     //    Create and set the new clip gxShape.
  505.     //
  506.     contentViewPortClipShape = GXNewRectangle(&viewRect);
  507.     GXSetViewPortClip(gcontentViewPort, contentViewPortClipShape);
  508.  
  509.     GXDisposeShape (contentViewPortClipShape);
  510. }
  511.  
  512.  
  513.  
  514. /**----- DoGrowWindow ------------------------------------------------------------------------
  515.  --
  516.  --        This function takes care of growing a window after the mouse has been pressed over
  517.  --        the grow icon.  It allows maximum growth of the document size or display size, whichever
  518.  --        is smaller. It allows minimum growth to (kMinWindowWidth,kMinWindowHeight) or the 
  519.  --        document size, whichever is larger. Finally, it adjusts and redraws the scroll bars 
  520.  --        for the new window size.
  521.  --
  522.  **/
  523. void DoGrowWindow(WindowPtr theWindow, Point where)
  524. {
  525.     Rect        growRect, windRect;
  526.     Rect        thePage;
  527.     short        width, height;
  528.     long        newSize;
  529.     Point        origin;
  530.  
  531.     thePage = ((MyWindowPeek)theWindow)->documentBoundsRect;
  532.  
  533.     width = thePage.right - thePage.left + kScrollBarWidth;
  534.     height = thePage.bottom - thePage.top + kScrollBarWidth;
  535.  
  536.     growRect = (**GetGrayRgn()).rgnBBox;
  537.     if (theWindow->portRect.left + width < growRect.right)
  538.        growRect.right = theWindow->portRect.left + width;
  539.         
  540.     if (theWindow->portRect.top + height < growRect.bottom)
  541.          growRect.bottom = theWindow->portRect.top + height;
  542.  
  543.     // Minimum size is (kMinWindowWidth,kMinWindowHeight) 
  544.     growRect.left = kMinWindowWidth;
  545.     growRect.top = kMinWindowHeight;
  546.     
  547.     // Make sure maximum size is at least minimum size
  548.     if (growRect.right < growRect.left) growRect.right = growRect.left;
  549.     if (growRect.bottom < growRect.top) growRect.bottom = growRect.top;
  550.  
  551.     /* Allow user to grow the window, then resize it */
  552.     newSize = GrowWindow(theWindow, where, &growRect);
  553.     
  554.     if (newSize != 0)
  555.     {
  556.         GrafPtr        saveport;
  557.  
  558.         InvalidateScrollBars(theWindow);
  559.         SizeWindow(theWindow, LoWord(newSize), HiWord(newSize), true);
  560.         InvalidateScrollBars(theWindow);
  561.         ResizeScrollBars(theWindow);
  562.  
  563.         // 
  564.         //    The user as grown the window, we need to update the clip gxShape of the contentviewPort
  565.         //    we attached to the window earlier in the CreateDocumentWindow function. If we did not
  566.         //    update the clip gxShape of the contentviewPort clip, we would draw through the scroll  
  567.         //    bars on the next update event.                                           (GX Scrolling)
  568.         //
  569.         ResetContentViewPortClip(theWindow);
  570.  
  571.         
  572.         /* reposition document */
  573.         origin = ((MyWindowPeek)theWindow)->origin;
  574.         width = theWindow->portRect.right - theWindow->portRect.left - origin.h - width + 1;
  575.         height = theWindow->portRect.bottom - theWindow->portRect.top - origin.v - height + 1;
  576.         if (width < 0) width = 0;
  577.         if (height < 0) height = 0;
  578.  
  579.         if ( (width > 0) || (height > 0) )
  580.         {
  581.             DoScroll(theWindow, width, height);
  582.             ResizeScrollBars(theWindow);
  583.         }
  584.     }
  585. }
  586.  
  587.  
  588. /**----- DoZoomWindow ------------------------------------------------------------------------
  589.  --
  590.  --        This function zooms a window. It follows the new human interface guidelines be 
  591.  --        dealing with multiple displays. To do this, every time the window is zoomed to the 
  592.  --        standard state, it recalculates the standard state based on the display that contains
  593.  --        the largest area of the window. This routine   was adapted from Macintosh Technical 
  594.  --        Note #79: "_ZoomWindow".
  595.  --
  596.  **/
  597. void DoZoomWindow(WindowPtr theWindow, short thePart)
  598. {
  599.     Rect                deviceRect, zoomRect;
  600.     Point                offset;
  601.     WStateDataHandle    windowState;
  602.         
  603.     SetPort(theWindow);
  604.     EraseRect(&theWindow->portRect);
  605.     if ( (thePart == inZoomOut) && (ColorQDAvail()) )
  606.     {
  607.         /* Get window location in global coordinates */
  608.         SetPt(&offset, 0, 0);
  609.         LocalToGlobal(&offset);
  610.         
  611.         deviceRect = GetDeviceRect(theWindow);
  612.  
  613.         zoomRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  614.         zoomRect.right += kScrollBarWidth-1;
  615.         zoomRect.bottom += kScrollBarWidth-1;
  616.  
  617.         OffsetRect(&zoomRect, -zoomRect.left, -zoomRect.top);    /* Adjust upper left to 0,0 */
  618.  
  619.         /* At least minimum window size */
  620.         if (zoomRect.right < kMinWindowWidth-1) zoomRect.right = kMinWindowWidth-1;
  621.         if (zoomRect.bottom < kMinWindowHeight-1) zoomRect.bottom = kMinWindowHeight-1;
  622.  
  623.         OffsetRect(&zoomRect, offset.h, offset.v);                /* Align to window */
  624.         
  625.         FitWindowOnDevice(&zoomRect, &deviceRect);
  626.  
  627.         windowState = (WStateDataHandle)((WindowPeek)theWindow)->dataHandle;
  628.         (**windowState).stdState = zoomRect;
  629.     }
  630.     ZoomWindow(theWindow, thePart, true);
  631.     InvalRect(&theWindow->portRect);
  632.  
  633.     ResizeScrollBars(theWindow);
  634.  
  635.     // 
  636.     //    The user as grown the window, we need to update the "gcontentviewPort" we attached to 
  637.     //    the window earlier in the CreateDocumentWindow (..) function. If we did not update, the
  638.     //    contentviewPort clip, we would draw through the scroll bars on the next update event. 
  639.     //                                                                            (GX Scrolling)
  640.     //
  641.     ResetContentViewPortClip(theWindow);
  642. }
  643.  
  644.  
  645.  
  646. /**----- FitWindowOnDevice -------------------------------------------------------------------
  647.  --
  648.  --        This routine takes two rectangles as parameters. windRect is the location of the 
  649.  --        window in global coordinates. deviceRect is the boundary of the device in global 
  650.  --        coordinates. This routine fits windRect inside deviceRect.  windRect is  modified, 
  651.  --        and upon completion, is where the window should be positioned.
  652.  --
  653.  --        Here's how the algorithm works:
  654.  --        Attempt to leave the window in the same location.  If the window doesn't fit inside
  655.  --        the deviceRect, move it to the upper left corner of deviceRect.  If the window still 
  656.  --        doesn't fit, resize windRect to fit inside the maxRect.
  657.  --
  658.  --        NOTE: Both rectangles must be in the same coordinate system.
  659.  --
  660.  **/
  661. void FitWindowOnDevice(Rect *windRect, Rect *deviceRect)
  662. {
  663.     Rect    theUnion;    
  664.  
  665.     UnionRect(windRect, deviceRect, &theUnion);
  666.     if (!EqualRect(deviceRect, &theUnion))            /* window contained on screen? */
  667.     {                                                /* no, move to upper left corner of maxRect */
  668.         OffsetRect(windRect, deviceRect->left-windRect->left, deviceRect->top-windRect->top);
  669.         UnionRect(windRect, deviceRect, &theUnion);
  670.         if (!EqualRect(deviceRect, &theUnion))        /* window contained on screen? */
  671.         {                                            /* no, resize window to fit */
  672.             if (windRect->right > deviceRect->right)
  673.                 windRect->right = deviceRect->right;
  674.             if (windRect->bottom > deviceRect->bottom)
  675.                 windRect->bottom = deviceRect->bottom;
  676.         }
  677.     }
  678. }
  679.  
  680.  
  681. /**----- GetDeviceRect -----------------------------------------------------------------------
  682.  --
  683.  --        This routine takes a WindowPtr as its parameter. It returns the boundary gxRectangle of
  684.  --        the device that contains the largest area of that window. The rect is returned in 
  685.  --        global coordinates.
  686.  --
  687.  **/
  688. Rect GetDeviceRect(WindowPtr theWindow)
  689. {
  690.     Rect        deviceRect, windRect, theSect;
  691.     GDHandle    nthDevice, dominantGDevice;
  692.     long        sectArea, greatestArea;
  693.     short        bias;
  694.     Point        offset;
  695.     
  696.     /* Get portRect in global coordinates */
  697.     windRect = theWindow->portRect;
  698.     SetPt(&offset, 0, 0);
  699.     LocalToGlobal(&offset);
  700.     OffsetRect(&windRect, offset.h, offset.v);
  701.  
  702.     bias = kTitleBarHeight;
  703.     windRect.top -= bias;
  704.     
  705.     /* This loop checks the window against all the gdRects in the gDevice list */
  706.     /* and remembers which gdRect contains the largest portion of the window   */
  707.     /* being zoomed. */
  708.     nthDevice = GetDeviceList();
  709.     greatestArea = 0;
  710.     while (nthDevice != nil)
  711.     {
  712.         if (TestDeviceAttribute(nthDevice, screenDevice))
  713.             if (TestDeviceAttribute(nthDevice, screenActive))
  714.             {
  715.                 SectRect(&windRect, &(**nthDevice).gdRect, &theSect);
  716.                 sectArea = (long)(theSect.right - theSect.left) *
  717.                                  (theSect.bottom - theSect.top);
  718.                 if (sectArea > greatestArea)
  719.                 {
  720.                     greatestArea = sectArea;
  721.                     dominantGDevice = nthDevice;
  722.                 }
  723.             }
  724.         nthDevice = GetNextDevice(nthDevice);
  725.     }
  726.  
  727.     /* Create a max zoom gxRectangle, accounting for menu bar height if on main screen */
  728.     if (dominantGDevice == GetMainDevice())
  729.         bias += GetMBarHeight();
  730.     SetRect(&deviceRect, (**dominantGDevice).gdRect.left+3,
  731.             (**dominantGDevice).gdRect.top+bias+3,
  732.             (**dominantGDevice).gdRect.right-3,
  733.             (**dominantGDevice).gdRect.bottom-3);
  734.     
  735.     return(deviceRect);
  736. }
  737.  
  738.  
  739. /**----- HandleKeyPress ----------------------------------------------------------------------
  740.  --
  741.  --        This function is called whenever a key is pressed. Since this program has no typed 
  742.  --        input, we are only concerned about command key equivalent menu selections.
  743.  --
  744.  **/
  745. void HandleKeyPress(EventRecord *theEvent)
  746. {
  747.     char        theChar;
  748.  
  749.     theChar = theEvent->message & charCodeMask;
  750.     if ((theEvent->modifiers & cmdKey)!=0)
  751.     {
  752.         AdjustMenus();
  753.         DoMenu(MenuKey(theChar));
  754.     }
  755. }
  756.  
  757.  
  758.  
  759. /**----- HandleDiskEvent ---------------------------------------------------------------------
  760.  --
  761.  --        This function checks whether the disk was successfully mounted. If it wasn't, the disk
  762.  --        initialization package is invoked.
  763.  --
  764.  **/
  765. void HandleDiskEvent(EventRecord *event)
  766. {
  767.     Point thePoint = {120, 120};
  768.     
  769.     if (HiWord(event->message) != noErr)
  770.     {
  771.         DILoad();
  772.         DIBadMount(thePoint, event->message);    /* thePoint is ignored in sys 7+ */
  773.         DIUnload();
  774.     }
  775. }
  776.  
  777.  
  778. /**----- HandleOSEvent -----------------------------------------------------------------------
  779.  --
  780.  --        This function is called when OSEvents are received. It handles suspend, resume, and mouse 
  781.  --        moved OSEvents.
  782.  --
  783.  **/
  784. void HandleOSEvent(EventRecord *theEvent)
  785. {
  786.     WindowPtr    theWindow;
  787.     
  788.     switch ((theEvent->message >> 24) & 0x000000ff)
  789.     {
  790.     case suspendResumeMessage:
  791.         if (theEvent->message & 0x00000001)        /* resume message */
  792.         {
  793.             SetCursor(&qd.arrow);
  794.             theWindow = FrontWindow();
  795.             if (theWindow != nil)
  796.                 ActivateWindow(theWindow, true);    /* Activate front window */
  797.             /* Copy contents of clipboard (if changed) to private scrap */
  798.         }
  799.         else    /* suspend message */
  800.         {
  801.             theWindow = FrontWindow();
  802.             if (theWindow != nil)
  803.                 ActivateWindow(theWindow, false);    /* Deactivate front window */
  804.             /* Move private scrap to clipboard */
  805.         }
  806.         break;
  807.     
  808.     case mouseMovedMessage:
  809.         break;
  810.     }
  811. }
  812.  
  813.  
  814. /**----- ActivateWindow ----------------------------------------------------------------------
  815.  --
  816.  --        This function activates or deactivates a window, and is called when either an 
  817.  --        activate/deactivate event or suspend/resume event is received. The parameters are a 
  818.  --        window pointer to the desired window, and a gxBoolean specifying whether to activate
  819.  --        or deactivate the window.
  820.  **/
  821. void ActivateWindow(WindowPtr theWindow, Boolean activate)
  822. {
  823.     if (theWindow == nil)    /* safety check */
  824.         return;
  825.  
  826.     if (activate)        /* activiate window */
  827.     {
  828.         /* Highlight controls */
  829.         DrawGrowIcon(theWindow);
  830.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 0);
  831.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 0);
  832.         /* Restore vertical bar or highlighting */
  833.         /* Enable appropriate menu items */
  834.     }
  835.     else    /* deactivate window */
  836.     {
  837.         /* Unhighlight controls */
  838.         DrawGrowIcon(theWindow);
  839.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 255);
  840.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 255);
  841.         /* Remove vertical bar or highlighting */
  842.         /* Disable appropriate menu items */
  843.     }
  844. }
  845.  
  846.  
  847.  
  848. /**----- DoMenu ------------------------------------------------------------------------------
  849.  --
  850.  --        This function is called when a menu item has been selected either with the mouse, 
  851.  --        or a keyboard equivalent.
  852.  --
  853.  **/
  854. void DoMenu(long menuChoice)
  855. {
  856.     short            theMenu;
  857.     short            theItem;
  858.     MenuHandle        appleMenu;
  859.     Str255            accName;
  860.     GrafPtr            savePort;
  861.  
  862.     theMenu = HiWord(menuChoice);
  863.     theItem = LoWord(menuChoice);
  864.     switch (theMenu)
  865.     {
  866.     case mApple:
  867.         if (theItem == iAbout)
  868.             Alert(rAboutBox, (ModalFilterProcPtr)nil);
  869.         else
  870.         {
  871.             appleMenu = GetMHandle(mApple);
  872.             if (appleMenu != nil)
  873.             {
  874.                 GetItem(appleMenu, theItem, accName);    /* Call desk accessory */
  875.                 GetPort(&savePort);
  876.                 OpenDeskAcc(accName);
  877.                 SetPort(savePort);
  878.             }
  879.         }
  880.         break;
  881.         
  882.     case mFile:
  883.         switch (theItem)
  884.         {
  885.         case iOpen:
  886.             DoOpenCommand();
  887.             break;
  888.         
  889.         case iClose:
  890.             CloseFrontWindow();
  891.             break;
  892.         
  893.         case iPageSetup:
  894.             break;
  895.         
  896.         case iPrint:
  897.             DoPrintCommand();
  898.             break;
  899.         
  900.         case iQuit:
  901.             ShutdownProgram();
  902.             break;
  903.         }
  904.         break;
  905.     }
  906.     HiliteMenu(0);
  907. }
  908.  
  909.  
  910.  
  911. void DoOpenCommand(void)
  912. {
  913. }
  914.  
  915.  
  916. void DoPrintCommand(void)
  917. {
  918. }
  919.  
  920.  
  921.  
  922. void PrintDocument(PicHandle thePicture)
  923. {
  924.  
  925. }
  926.  
  927.  
  928. PicHandle ReadDocument(FSSpecPtr mySpec)
  929. {
  930.  
  931. }
  932.  
  933.  
  934.  
  935. /**----- GetWindowBoundsShape ----------------------------------------------------------------
  936.  --
  937.  --        This function returns a fixed gxPoint gxRectangle which represents the portRect of the
  938.  --        window. The gxShape returned is used as the new clip gxShape for the gcontentViewPort.
  939.  --                                                                            (GX Scrolling) 
  940.  **/
  941. void GetWindowBoundsShape(WindowPtr myWindow, gxRectangle *boundingBoxPtr)
  942. {
  943.     GrafPtr                oldPort;
  944.     Rect                qdBounds;
  945.     gxRectangle            gxBounds;
  946.     gxValidationLevel     currentValidation;
  947.  
  948.     GetPort(&oldPort);
  949.     SetPort(myWindow);
  950.  
  951.     qdBounds = myWindow->portRect;        // this is in globals coordinates
  952.  
  953.      //
  954.      //    Unfortunately, GXConvertQDPoint(..) will not survive validation with the QD GX ß2
  955.      //    seed. Therefore, we get the validation level set up by the application,  and turn the
  956.      //    validation off. We will reset the validation to it's original setting below.
  957.      //
  958.      //    This problem has already been fixed in the QD GX ß3 build, therefore this work around 
  959.      //    will be removed at ß3. Details about the parameters for the GXConvertQDPoint (..) call
  960.      //    can be found in the QD GX ß2 Graphics Notes within the "• Open Me First •" folder.
  961.      // 
  962.     currentValidation = GXGetValidation();
  963.       if (currentValidation) GXSetValidation(gxNoValidation);
  964.      
  965.     //
  966.     //  Convert the global Quickdraw coordinates to local fixed coordinates. 
  967.     //
  968.     GXConvertQDPoint((Point *) &qdBounds.top, 0, (gxPoint *) &gxBounds.left);
  969.     GXConvertQDPoint((Point *) &qdBounds.bottom, 0, (gxPoint *) &gxBounds.right);
  970.  
  971.     //
  972.     //    Reset the validation to the original setting.
  973.     //
  974.        if (currentValidation) GXSetValidation(currentValidation);
  975.  
  976.     *boundingBoxPtr = gxBounds;
  977.  
  978.     SetPort(oldPort);
  979. }
  980.  
  981.  
  982.  
  983. /**----- CreateThePageOfGXShapes -------------------------------------------------------------
  984.  --
  985.  --        This function creates a GX picture containing the shapes which will be displayed
  986.  --        within our window. In this case, all of the shapes will be rectangles
  987.  --                                                                         (GX Addition)
  988.  **/
  989. gxShape CreateThePageOfGXShapes (gxShape thePage)
  990. {
  991.     gxShape        tempRectangleShape;
  992.      gxRectangle     rectangleGeometry = {0, 0, ff(100), ff(100)};    
  993.     short        loop;
  994.     
  995.     //
  996.     //    If the picture passed in has not been created, create an empty GX picture. We set
  997.     //    the "gxUniqueItemsShape" attribute because we are adding the same gxRectangle multiple
  998.     //    times. This guarantees that each rectagnle will have a "unique" reference within
  999.     //    the picture. Otherwise, you would only see the last gxRectangle added to the picture.
  1000.     //
  1001.     if (thePage == nil) 
  1002.     {
  1003.         thePage = GXNewShape(gxPictureType);
  1004.         GXSetShapeAttributes(thePage, gxUniqueItemsShape);
  1005.     }
  1006.     
  1007.     //
  1008.     //    Create a gxRectangle: rotated 45 degrees, with a close frame fill, and a pen width of 4.
  1009.     //
  1010.     tempRectangleShape = GXNewRectangle(&rectangleGeometry); 
  1011.     GXRotateShape(tempRectangleShape, ff(45), ff(50), ff(50));
  1012.     GXSetShapeFill(tempRectangleShape, gxClosedFrameFill);
  1013.     GXSetShapePen(tempRectangleShape, ff(4));
  1014.     GXMoveShape(tempRectangleShape, ff(35), ff(35));
  1015.  
  1016.     //
  1017.     //    Set the gxColor of the gxRectangle by calling SetShapeCommonColor (..), and add the 
  1018.     //    gxRectangle to our picture.
  1019.     //
  1020.     for (loop =1; loop <= 11; loop++)
  1021.     {
  1022.         SetShapeCommonColor (tempRectangleShape, loop + 5);
  1023.         AddToShape(thePage, tempRectangleShape);
  1024.         GXMoveShape(tempRectangleShape, ff(60), ff(105));
  1025.     }
  1026.  
  1027.     GXDisposeShape (tempRectangleShape);
  1028.     
  1029.     return (thePage);
  1030. }
  1031.     
  1032.  
  1033. /**----- CreateDocumentWindow ----------------------------------------------------------------
  1034.  --
  1035.  --        This function creates a new document window.  We attached a parent gxViewPort to the 
  1036.  --        window and a child gxViewPort to it. Having the application maintain the child gxViewPort's
  1037.  --        clip gxShape and gxMapping will allow use to draw within the scroll bars & update it's
  1038.  --        gxMapping to reflect scrolling of the shapes.
  1039.  --
  1040.  --        The parameters: we ignore the PicHandle at this gxPoint and the str63 containing the 
  1041.  --        name for the title bar of the window is used.
  1042.  --
  1043.  --        A gxBoolean is returned indicating success.  Failure may result from an running out of 
  1044.  --        memory in the gxHeap.
  1045.  --
  1046.  **/
  1047. Boolean CreateDocumentWindow(PicHandle thePicture, Str63 name)
  1048. {
  1049.     WindowPtr        theWindow;
  1050.     ControlHandle    hControl, vControl;
  1051.     Rect            controlRect, deviceRect, windRect, docRect = {0, 0, 1000, 1000};
  1052.     Point            origin;
  1053.  
  1054.     /* Allocate space for window */
  1055.     theWindow = (WindowPtr)NewPtr(sizeof(MyWindowRecord));
  1056.     if (theWindow == nil)
  1057.     {
  1058.         ErrorAlert(kOutOfMemoryErr, false);
  1059.         return(false);
  1060.     }
  1061.     GetNewWindow(rDocumentWindow, theWindow, (WindowPtr)-1);
  1062.  
  1063.     ((MyWindowPeek)theWindow)->documentBoundsRect = docRect;
  1064.     SetPt(&((MyWindowPeek)theWindow)->origin, 0, 0);
  1065.     SetWTitle(theWindow, name);
  1066.  
  1067.     windRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  1068.  
  1069.     windRect.right += kScrollBarWidth-1;
  1070.     windRect.bottom += kScrollBarWidth-1;
  1071.     OffsetRect(&windRect, -windRect.left, -windRect.top);    /* Adjust upper left to 0,0 */
  1072.     if (windRect.right < kMinWindowWidth-1) windRect.right = kMinWindowWidth-1;
  1073.     if (windRect.bottom < kMinWindowHeight-1) windRect.bottom = kMinWindowHeight-1;
  1074.  
  1075.     /* Allocate space for HORIZONTAL scroll bar */
  1076.     SetRect(&controlRect, 0, 0, 100, 10);
  1077.     hControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  1078.     ((MyWindowPeek)theWindow)->hScrollBar = hControl;
  1079.     if (hControl == nil)
  1080.     {
  1081.         CloseWindow(theWindow);
  1082.         DisposePtr((Ptr)theWindow);
  1083.         ErrorAlert(kOutOfMemoryErr, false);
  1084.         return(false);
  1085.     }
  1086.     
  1087.     /* Allocate space for VERTICAL scroll bar */
  1088.     SetRect(&controlRect, 0, 0, 10, 100);
  1089.     vControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  1090.     ((MyWindowPeek)theWindow)->vScrollBar = vControl;
  1091.     if (vControl == nil)
  1092.     {
  1093.         DisposeControl(hControl);
  1094.         CloseWindow(theWindow);
  1095.         DisposePtr((Ptr)theWindow);
  1096.         ErrorAlert(kOutOfMemoryErr, false);
  1097.         return(false);
  1098.     }
  1099.  
  1100.     /* POSITION the new window */
  1101.     if (FrontWindow() == nil)        /* no windows open, use default position */
  1102.     {                                /* Align to upper left of main device */
  1103.         OffsetRect(&windRect, 2, 2 + kTitleBarHeight+GetMBarHeight());
  1104.         deviceRect = qd.screenBits.bounds;
  1105.         deviceRect.left += 3;
  1106.         deviceRect.top += 3+GetMBarHeight()+kTitleBarHeight;
  1107.         deviceRect.right -= 3;
  1108.         deviceRect.bottom -= 3;
  1109.     }
  1110.     else    /* Position down and right from frontmost window */
  1111.     {
  1112.         SetPort(FrontWindow());
  1113.         SetPt(&origin, 0, 0);
  1114.         LocalToGlobal(&origin);
  1115.         origin.h += kNewWindowOffset;
  1116.         origin.v += kNewWindowOffset;
  1117.         OffsetRect(&windRect, origin.h, origin.v);
  1118.         deviceRect = GetDeviceRect(FrontWindow());
  1119.     }
  1120.  
  1121.     /* Adjust size and position for display        */
  1122.     /* If not enough room for entire window:    */
  1123.     /* 1. Position in upper left                */
  1124.     /* 2. Resize to fit on screen                */
  1125.     FitWindowOnDevice(&windRect, &deviceRect);
  1126.     MoveWindow(theWindow, windRect.left, windRect.top, true);
  1127.     SizeWindow(theWindow, windRect.right-windRect.left,
  1128.                 windRect.bottom-windRect.top, false);
  1129.     
  1130.     ResizeScrollBars(theWindow);        /* Initialize Scroll Bars */
  1131.  
  1132.     ShowControl(hControl);
  1133.     ShowControl(vControl);
  1134.     ShowWindow(theWindow);
  1135.  
  1136.     //
  1137.     //    We need to attach a couple of viewPorts to the window to allow our
  1138.     //    GX shapes to be clipped and scrolled correctly.     (GX Scrolling)    
  1139.     //
  1140.     {
  1141.         gxRectangle    viewRect;
  1142.         gxViewPort    windowParentViewPort;
  1143.         gxShape        contentViewPortShape;
  1144.         
  1145.         //
  1146.         //    Get a rectangle shape which represents the portRect of the
  1147.         //    window. This shape will be used as the clip shape for the
  1148.         //    "gcontentViewPort". This gxViewPort will have all of our
  1149.         //    GX objects drawn to.
  1150.         //
  1151.         GetWindowBoundsShape(theWindow, &viewRect);
  1152.  
  1153.         //
  1154.         //     Adjust our viewRect to accommodate the scroll bars
  1155.         //
  1156.         viewRect.right -= ff(kScrollBarWidth - 1);    
  1157.         viewRect.bottom -= ff(kScrollBarWidth - 1);
  1158.  
  1159.         //
  1160.         //    Add a viewPort to the window. This will enable the
  1161.         //    user to move the window around and have our GX objects
  1162.         //    drawn into the window.
  1163.         //    
  1164.         windowParentViewPort = GXNewWindowViewPort(theWindow);
  1165.  
  1166.         //
  1167.         //    Create a second viewPort and attached it to the "parent"
  1168.         //    viewPort of our window. You cannot manipulate the parent
  1169.         //    viewPort attached to a window, but you can manipulate it's
  1170.         //    child. We will manipulate the clip and gxMapping of this viewPort
  1171.         //    when the user resizes the window or scrolls it's contents. Also, we
  1172.         //    need this child viewPort because we want to set the clip shape of the
  1173.         //    window to reside within the scroll bars, not on top of them, which would
  1174.         //    be the case if we only used the parent viewPort.
  1175.         // 
  1176.         gcontentViewPort = GXNewViewPort(GXGetViewPortViewGroup(windowParentViewPort));
  1177.          
  1178.         //
  1179.         //    Set up the shape, clip and, mapping of our "gcontentViewPort". We will
  1180.         //    then attached it to the "parent" viewPort of the window.
  1181.         //
  1182.         contentViewPortShape = GXNewRectangle(&viewRect);
  1183.         GXSetViewPortClip(gcontentViewPort, contentViewPortShape);
  1184.         GXSetViewPortMapping(gcontentViewPort, nil);
  1185.         GXSetViewPortParent(gcontentViewPort, windowParentViewPort);
  1186.         GXDisposeShape (contentViewPortShape);
  1187.  
  1188.         //
  1189.         //    By calling SetDefaultViewPort (..), all shapes we create will 
  1190.         //    be automatically drawn to "gcontentViewPort".
  1191.         // 
  1192.         GXIgnoreGraphicsNotice(transform_already_set);
  1193.         SetDefaultViewPort(gcontentViewPort);            
  1194.         GXPopGraphicsNotice();
  1195.     
  1196.         gthePage = CreateThePageOfGXShapes (nil);
  1197.     }
  1198.  
  1199.     return(true);
  1200. }
  1201.  
  1202.  
  1203. /**----- CloseFrontWindow --------------------------------------------------------------------
  1204.  --
  1205.  --        This function closes the frontmost window and disposes of the window record allocated
  1206.  --        on the gxHeap for it.
  1207.  --
  1208.  **/
  1209. void CloseFrontWindow(void)
  1210. {
  1211.     WindowPtr    theWindow;
  1212.     
  1213.     theWindow = FrontWindow();
  1214.     if (theWindow!=nil)
  1215.     {
  1216.         CloseWindow(theWindow);
  1217.         DisposePtr((Ptr)theWindow);
  1218.     }
  1219. }
  1220.  
  1221.  
  1222.  
  1223. /**----- DrawWindow --------------------------------------------------------------------------
  1224.  --
  1225.  --        This function draws the contents of the window without overwriting the scroll bars.
  1226.  --
  1227.  **/
  1228. void DrawWindow(WindowPtr theWindow)
  1229. {
  1230.     PicHandle    thePicture;
  1231.     Rect        tempRect;
  1232.     Point        origin;
  1233.     RgnHandle    saveClip;
  1234.  
  1235.     SetPort(theWindow);
  1236.  
  1237.     saveClip = NewRgn();        /* Remove scroll bar areas from clipRgn */
  1238.     GetClip(saveClip);
  1239.     tempRect = theWindow->portRect;
  1240.     tempRect.right -= (kScrollBarWidth-1);
  1241.     tempRect.bottom -= (kScrollBarWidth-1);
  1242.     ClipRect(&tempRect);
  1243.  
  1244.     SetClip(saveClip);            /* Restore clipRgn */
  1245.     DisposeRgn(saveClip);        
  1246.  
  1247.     //
  1248.     //    Draw the shapes contained within our GX picture gxShape - gthePage (GX Addition)
  1249.     // 
  1250.     GXDrawShape (gthePage);
  1251. }
  1252.  
  1253.  
  1254. /**----- AdjustMenus -------------------------------------------------------------------------
  1255.  --
  1256.  --        This function is called immediately before each time the user makes a menu selection.
  1257.  --        It enables/disables the appropriate menu items based on the current state of the 
  1258.  --        program. In version 1.0, we do not update the menus. We only support "quit".
  1259.  **/
  1260. void AdjustMenus(void)
  1261. {
  1262. }
  1263.  
  1264.  
  1265.  
  1266. /**----- FileRoutinesAvail -------------------------------------------------------------------
  1267.  --
  1268.  --        This function is used before calling FSSpec routines to see if they are available.
  1269.  --        Note that MPW 3.2 and THINK C 5.0 both include glue that let you use Gestalt even if
  1270.  --        it is not in ROM or in the System File. If you are not using one of these environments, 
  1271.  --        and you don't have Gestalt glue, you will need to use the TrapAvailable check (as shown
  1272.  --        in Inside Macintosh VI 3-8) to determine whether the Gestalt call exists before calling
  1273.  --         it.
  1274.  **/
  1275. Boolean FileRoutinesAvail(void)
  1276. {
  1277.     long    response;
  1278.     
  1279.     if (Gestalt(gestaltFSAttr, &response) == noErr)
  1280.         if ((response >> gestaltHasFSSpecCalls) & 0x00000001)
  1281.             if (Gestalt(gestaltStandardFileAttr, &response) == noErr)
  1282.                 if ((response >> gestaltStandardFile58) & 0x00000001)
  1283.                     return(true);
  1284.     return(false);
  1285. }
  1286.  
  1287.  
  1288.  
  1289. /**----- ColorQDAvail ------------------------------------------------------------------------
  1290.  --
  1291.  --        This function is used before calling Color QuickDraw routines to see if they are 
  1292.  --        available.  Note that MPW 3.2 and THINK C 5.0 both include glue that let you use
  1293.  --        Gestalt even if it is not in ROM or in the System File. If you are not using one of 
  1294.  --        these environments, and you don't have Gestalt glue, you will need to use the 
  1295.  --        TrapAvailable check (as shown in Inside Macintosh VI 3-8) to determine whether the
  1296.  --     Gestalt call exists before calling it.
  1297.  --
  1298.  **/
  1299. Boolean ColorQDAvail(void)
  1300. {
  1301.     long    response;
  1302.     
  1303.     if (Gestalt(gestaltQuickdrawVersion, &response) == noErr)
  1304.         if ((response & 0x0000ffff) >= gestalt8BitQD)
  1305.             return(true);
  1306.     return(false);
  1307. }
  1308.  
  1309.  
  1310.  
  1311. /**----- ErrorAlert --------------------------------------------------------------------------
  1312.  --
  1313.  --        This function displays an error message in an alert.  The error number corresponds
  1314.  --         to an error message in a 'str#' resource.  This message is displayed in a dialog box.
  1315.  --          The Boolean parameter is true for a fatal error, and will cause the program to 
  1316.  --        immediately terminate instead of returning.
  1317.  --
  1318.  **/
  1319. void ErrorAlert(short errNumber, Boolean fatal)
  1320. {
  1321.     Str255    errorString;
  1322.     
  1323.     GetIndString(errorString, rErrorStrings, errNumber);
  1324.         
  1325.     ParamText(errorString, "\p", "\p", "\p");
  1326.     if (fatal)
  1327.     {
  1328.         StopAlert(rFatalErrorAlert, nil);
  1329.         ExitToShell();
  1330.     }
  1331.     else
  1332.         NoteAlert(rNonFatalErrorAlert, nil);
  1333. }
  1334.  
  1335.  
  1336.  
  1337. /**----- ShutdownProgram ---------------------------------------------------------------------
  1338.  --
  1339.  --        This function is called before normal termination of the program.  It sets the event
  1340.  --        loop done variable to true, so the program will exit at the end of the event loop. We
  1341.  --        call CloseFrontWindow() to dispose of our window and data structure containing our
  1342.  --        document information.
  1343.  --
  1344.  --        If this program had editing capabilities, this is where the user would be asked if 
  1345.  --        he wanted to save any changed documents before quitting.
  1346.  --
  1347.  **/
  1348. void ShutdownProgram(void)
  1349. {
  1350.     WindowPtr    theWindow;
  1351.     
  1352.     gDone = true;
  1353.     
  1354.     //     
  1355.     //    If we created a GX picture which contains our window full of information, we wnat to
  1356.     //    dispose of it, by callling GXDisposeShape. We call DisposeCommonColor () because we 
  1357.     //    initialized the common colors library earlier in the QuickDrawGXInit function.
  1358.     //                                                                         (GX Addition)
  1359.     if (gthePage != nil) GXDisposeShape(gthePage);  
  1360.  
  1361.        DisposeCommonColors();
  1362.  
  1363.     //
  1364.     //    This function call will dispose of the data contained in the window.
  1365.     //
  1366.     CloseFrontWindow();
  1367.     
  1368.     //    
  1369.     //     Deallocate all of the default data and memory structures for the GX 
  1370.     //    graphics and layout system.                                            (GX Addition)
  1371.     //
  1372.     GXExitGraphics();        
  1373.     GXDisposeGraphicsClient(gGraphicsClient);
  1374. }
  1375.